package excel

import (
	"data-system/common"
	"data-system/config"
	"data-system/dao"
	"data-system/meta"
	"data-system/models"
	"data-system/serial_handle"
	"data-system/tools"
	"fmt"
	"log"
	"strconv"

	"github.com/samber/lo"
)

func DBToExcel(nodeType string, skipConflictValid bool) error {
	serialMeta := meta.GetSerialMeta(nodeType)
	if serialMeta == nil {
		log.Println(fmt.Errorf("%v没有序列化元数据", nodeType))
		return fmt.Errorf("%v没有序列化元数据", nodeType)
	}
	dbAllRows, err := dao.QueryAll(nodeType)
	if err != nil {
		log.Fatal(err.Error())
		return err
	}
	var conflictRows = make([]*models.NodeData, 0)
	if !skipConflictValid {
		excelRows, err := LoadExcel(nodeType, serialMeta.DataLine)
		if err != nil {
			log.Println(fmt.Errorf("本地文件数据读取失败,%v", err))
			return fmt.Errorf("本地文件数据读取失败,%v", err)
		}
		if len(excelRows) > 0 {
			group := lo.Associate(excelRows, func(item models.ExcelData) (int64, *models.ExcelData) {
				id, _ := strconv.Atoi(item.Row["id"])
				return int64(id), &item
			})
			for _, dbAllRow := range dbAllRows {
				if len(dbAllRow.Md5) > 0 && dbAllRow.Stat == common.StatUpdate {
					excelRow := group[dbAllRow.Id]
					if excelRow != nil && tools.Md5(excelRow.OriginRow) != dbAllRow.Md5 {
						conflictRows = append(conflictRows, &dbAllRow)
					}
				}
			}
		}
	}
	contents, datas, err := convertExcelFileContents(nodeType, serialMeta, dbAllRows)
	if err != nil {
		return fmt.Errorf("DB数据转Excel数据异常：nodeType="+nodeType, err)
	}
	if len(conflictRows) > 0 {
		WriteConflictData(nodeType, contents)
		return fmt.Errorf("DB同步到Excel出现冲突：nodeType=" + nodeType)
	}
	//验证冲突
	WriteConfigData(nodeType, contents)
	err = dao.BatchSave(datas)
	if err != nil {
		log.Println(err.Error())
		return err
	}
	return nil
}

func ExcelToDB(nodeType string, skipConflictValid bool) (bool, error) {
	var dbRows = make([]models.NodeData, 0)
	serialMeta := meta.GetSerialMeta(nodeType)
	if serialMeta == nil {
		log.Println(fmt.Errorf("%v没有序列化元数据", nodeType))
		return false, fmt.Errorf("%v没有序列化元数据", nodeType)
	}
	excelRows, err := LoadExcel(nodeType, serialMeta.DataLine)
	if err != nil {
		log.Println(fmt.Errorf("本地文件数据读取失败,%v", err))
		return false, fmt.Errorf("本地文件数据读取失败,%v", err)
	}
	convertExcelDBRows, err := serial_handle.ExchangeEncodes(nodeType, excelRows)
	if err != nil {
		log.Println(err.Error())
		return false, err
	}
	//验证冲突
	var conflictRows = make([]*models.NodeData, 0)
	if !skipConflictValid {
		dbAllRows, _ := dao.QueryAll(nodeType)
		dbFilterRows := lo.Filter(dbAllRows, func(dbRow models.NodeData, _ int) bool {
			return dbRow.Stat == common.StatUpdate && len(dbRow.Md5) > 0
		})
		if len(dbFilterRows) > 0 {
			group := lo.Associate(dbFilterRows, func(dbRow models.NodeData) (int64, *models.NodeData) {
				return dbRow.Id, &dbRow
			})
			for _, convertExcelDBRow := range convertExcelDBRows {
				dbRow := group[convertExcelDBRow.Id]
				if dbRow != nil && convertExcelDBRow.Md5 != dbRow.Md5 && dbRow.Stat == common.StatUpdate {
					conflictRows = append(conflictRows, dbRow)
				}
			}
			if len(conflictRows) > 0 {
				contents, _, err := convertExcelFileContents(nodeType, serialMeta, dbAllRows)
				if err != nil {
					return false, fmt.Errorf("DB数据转Excel数据异常：nodeType="+nodeType, err)
				}
				WriteConflictData(nodeType, contents)
				return true, fmt.Errorf("Excel同步到数据库出现冲突：nodeType=" + nodeType)
			}
		}
	}
	dbRows = append(dbRows, convertExcelDBRows...)
	err = dao.BatchSave(dbRows)
	if err != nil {
		log.Println(err.Error())
		return false, err
	}
	return false, nil
}

func IsConflict(nodeType string) bool {
	fileUri := config.Cfg().ConflictDir + "/" + nodeType + config.Cfg().FileConflictSuffix
	exists := tools.IsFileExists(fileUri)
	return exists
	//err := tools.CreateDirIfNotExist(ctx.ConflictDir)
	//if err != nil {
	//	log.Fatal(err.Error())
	//}
	//files, err := tools.ReadFiles(ctx.FileConflictSuffix, ctx.ConflictDir)
	//if err != nil {
	//	log.Fatal(err.Error())
	//}
	//_, exist := lo.Find(files, func(nt string) bool {
	//	return nt == nodeType
	//})
	//return exist
}

func convertExcelFileContents(nodeType string, serialMeta *models.SerialMeta, dbRows []models.NodeData) ([][]string, []models.NodeData, error) {
	var cDBRows = make([]models.NodeData, 0)
	var syncExcelRows = serialMeta.TbHeaders
	for _, dbAllRow := range dbRows {
		convertDBRow, err := serial_handle.ExchangeDecode(nodeType, dbAllRow)
		if err != nil {
			log.Println(err.Error())
			return nil, nil, err
		}
		syncExcelRows = append(syncExcelRows, convertDBRow.OriginRow)
		dbAllRow.Md5 = tools.Md5(convertDBRow.OriginRow)
		dbAllRow.Stat = common.StatNone
		cDBRows = append(cDBRows, dbAllRow)
	}
	return syncExcelRows, cDBRows, nil
}
